package impl

import (
	"context"
	"errors"
	"github.com/samber/lo"
	"github.com/sirupsen/logrus"
	"monoblog/common"
	"monoblog/common/register"
	"monoblog/config"
	"monoblog/domain/dao"
	"monoblog/domain/model"
	"monoblog/domain/service"
)

func init() {
	register.RegisterInstance[service.InterestService]("InterestService", func() service.InterestService {
		return &InterestServiceImpl{
			interestRepository:        dao.NewUserInterestRepository(),
			collectRelationRepository: dao.NewCollectRelationRepository(),
			articleRepository:         dao.NewArticleRepository(),
			commentRepository:         dao.NewCommentRepository(),
			userRepository:            dao.NewUserRepository(),
		} // 返回唯一实例
	})
}

type InterestServiceImpl struct {
	interestRepository        *dao.UserInterestRepository
	collectRelationRepository *dao.CollectRelationRepository
	articleRepository         *dao.ArticleRepository
	commentRepository         *dao.CommentRepository
	userRepository            *dao.UserRepository
}

// UserToFollow 当前用户去关注id用户
// 当前用户userId 关注列表add followId
// followId 粉丝列表add 当前用户userId
func (s *InterestServiceImpl) UserToFollow(ctx context.Context, followId string, userId string) error {
	if followId == userId {
		return errors.New("关注/取消关注的对象不能是自己")
	}
	// 当前用户userId 关注列表add followId
	err := s.interestRepository.AppendFollowId(followId, userId)
	if err != nil {
		return err
	}
	// followId 粉丝列表add 当前用户userId
	err = s.interestRepository.AppendFansId(userId, followId)
	if err != nil {
		return err
	}
	// 通知关注者，当前用户userId 关注了 followId
	go func() {
		service.GetMomentPublishService().PublishWithFollow(ctx, followId, userId)
	}()

	return nil
}

// UserCancelFollow 当前用户去取消关注id用户
func (s *InterestServiceImpl) UserCancelFollow(ctx context.Context, followId string, userId string) error {
	if followId == userId {
		return errors.New("关注/取消关注的对象不能是自己")
	}
	// 当前用户userId 关注列表remove followId
	err := s.interestRepository.RemoveFollowId(followId, userId)
	if err != nil {
		return err
	}
	// followId 粉丝列表remove 当前用户userId
	err = s.interestRepository.RemoveFansId(userId, followId)
	if err != nil {
		return err
	}
	return nil
}

// UserToBlack 当前用户去拉黑id用户
func (s *InterestServiceImpl) UserToBlack(ctx context.Context, blackId string, userId string) error {
	if blackId == userId {
		return errors.New("拉黑/取消拉黑的对象不能是自己")
	}
	// 当前用户userId 黑名单add blackId
	err := s.interestRepository.AppendBlack(blackId, userId)
	if err != nil {
		return err
	}
	return nil
}

// UserCancelBlack 当前用户去取消拉黑id用户
func (s *InterestServiceImpl) UserCancelBlack(ctx context.Context, blackId string, userId string) error {
	if blackId == userId {
		return errors.New("拉黑/取消拉黑的对象不能是自己")
	}
	// 当前用户userId 黑名单remove blackId
	err := s.interestRepository.RemoveBlackId(blackId, userId)
	if err != nil {
		return err
	}
	return nil
}

// FavoriteTheArticle 收藏文章
func (s *InterestServiceImpl) FavoriteTheArticle(ctx context.Context, blogId string, userId string) error {
	collectRelation := &model.CollectRelation{
		UserId:      userId,
		TargetId:    blogId,
		CollectType: model.BLOG_FAVORITE.String(),
	}
	if exists, err := s.collectRelationRepository.Exists(collectRelation); err != nil {
		return err
	} else if exists {
		logrus.Infof("[aid: %s] 重复收藏文章:%s", ctx.Value("aid"), blogId)
		return nil
	}
	err := s.collectRelationRepository.Add(collectRelation)
	if err != nil {
		return err
	}

	go func() { //收藏量+1
		err0 := s.articleRepository.UpdateBlogFavoriteCount(blogId, 1)
		if err0 != nil {
			logrus.Errorf("[aid: %s] UpdateBlogFavoriteCount 时出错. err = %v", ctx.Value("aid"), err0.Error())
		}
		// 将文章id加入等待更新队列
		config.GetRedisClient().SAdd(context.Background(), common.REDIS_KEY_WAIT_FOR_UPDATE_BLOG, blogId)
	}()

	//通知文章作者，文章被收藏了
	go func() {
		service.GetMomentPublishService().PublishWithFavorite(ctx, userId, blogId)
	}()

	return nil
}

// CancelFavoriteTheArticle 取消收藏文章
func (s *InterestServiceImpl) CancelFavoriteTheArticle(ctx context.Context, blogId string, userId string) error {
	collectRelation := &model.CollectRelation{
		UserId:      userId,
		TargetId:    blogId,
		CollectType: model.BLOG_FAVORITE.String(),
	}
	deleted, err := s.collectRelationRepository.Delete(collectRelation)
	if err != nil {
		return err
	}

	if deleted {
		go func() { //收藏量-1
			err0 := s.articleRepository.UpdateBlogFavoriteCount(blogId, -1)
			if err0 != nil {
				logrus.Errorf("[aid: %s] UpdateBlogFavoriteCount 时出错. err = %v", ctx.Value("aid"), err0.Error())
			}
			// 将文章id加入等待更新队列
			config.GetRedisClient().SAdd(context.Background(), common.REDIS_KEY_WAIT_FOR_UPDATE_BLOG, blogId)

		}()
	}
	return nil
}

// LikeTheArticle 给文章点赞
func (s *InterestServiceImpl) LikeTheArticle(ctx context.Context, blogId string, userId string) error {
	collectRelation := &model.CollectRelation{
		UserId:      userId,
		TargetId:    blogId,
		CollectType: model.BLOG_LIKE.String(),
	}
	if exists, err := s.collectRelationRepository.Exists(collectRelation); err != nil {
		return err
	} else if exists {
		logrus.Infof("[aid: %s] 重复点赞文章:%s", ctx.Value("aid"), blogId)
		return nil
	}

	err := s.collectRelationRepository.Add(collectRelation)
	if err != nil {
		return err
	}
	go func() { //点赞量+1
		err0 := s.articleRepository.UpdateBlogLikeCount(blogId, 1)
		if err0 != nil {
			logrus.Errorf("[aid: %s] UpdateBlogLikeCount 时出错. err = %v", ctx.Value("aid"), err0.Error())
		}
		// 将文章id加入等待更新队列
		config.GetRedisClient().SAdd(context.Background(), common.REDIS_KEY_WAIT_FOR_UPDATE_BLOG, blogId)

	}()
	return nil
}

// CancelLikeTheArticle 取消给文章点赞
func (s *InterestServiceImpl) CancelLikeTheArticle(ctx context.Context, blogId string, userId string) error {
	collectRelation := &model.CollectRelation{
		UserId:      userId,
		TargetId:    blogId,
		CollectType: model.BLOG_LIKE.String(),
	}
	deleted, err := s.collectRelationRepository.Delete(collectRelation)
	if err != nil {
		return err
	}
	if deleted {
		go func() { //点赞量-1
			err0 := s.articleRepository.UpdateBlogLikeCount(blogId, -1)
			if err0 != nil {
				logrus.Errorf("[aid: %s] UpdateBlogLikeCount 时出错. err = %v", ctx.Value("aid"), err0.Error())
			}
			// 将文章id加入等待更新队列
			config.GetRedisClient().SAdd(context.Background(), common.REDIS_KEY_WAIT_FOR_UPDATE_BLOG, blogId)
		}()
	}
	return nil
}

// LikeTheComment 给评论点赞
func (s *InterestServiceImpl) LikeTheComment(ctx context.Context, commentId string, userId string) error {
	collectRelation := &model.CollectRelation{
		UserId:      userId,
		TargetId:    commentId,
		CollectType: model.COMMENT_LIKE.String(),
	}
	if exists, err := s.collectRelationRepository.Exists(collectRelation); err != nil {
		return err
	} else if exists {
		logrus.Infof("[aid: %s] 重复点赞评论:%s", ctx.Value("aid"), commentId)
		return nil
	}
	err := s.collectRelationRepository.Add(collectRelation)
	if err != nil {
		return err
	}
	go func() { //点赞量+1
		err0 := s.commentRepository.UpdateLikeCount(commentId, 1)
		if err0 != nil {
			logrus.Errorf("[aid: %s] UpdateLikeCount 时出错. err = %v", ctx.Value("aid"), err0.Error())
		}
	}()
	return nil
}

// CancelLikeTheComment 取消给评论点赞
func (s *InterestServiceImpl) CancelLikeTheComment(ctx context.Context, commentId string, userId string) error {
	collectRelation := &model.CollectRelation{
		UserId:      userId,
		TargetId:    commentId,
		CollectType: model.COMMENT_LIKE.String(),
	}
	deleted, err := s.collectRelationRepository.Delete(collectRelation)
	if err != nil {
		return err
	}
	if deleted {
		go func() { //点赞量-1
			err0 := s.commentRepository.UpdateLikeCount(commentId, -1)
			if err0 != nil {
				logrus.Errorf("[aid: %s] UpdateLikeCount 时出错. err = %v", ctx.Value("aid"), err0.Error())
			}
		}()
	}
	return nil
}

// StatsAtComment 是否已点赞
func (s *InterestServiceImpl) StatsAtComment(ctx context.Context, commentId string, userId string) (map[string]bool, error) {
	query := &model.CollectQuery{
		UserId:      userId,
		SubTargetId: commentId,
		CollectTypes: []string{
			model.COMMENT_LIKE.String(),
		},
	}
	//是否已点赞
	list, err := s.collectRelationRepository.FindListByQuery(query)
	if err != nil {
		logrus.Errorf("[aid: %s] FindListByQuery 时出错. err = %v", ctx.Value("aid"), err.Error())
		return nil, err
	}

	return map[string]bool{
		model.COMMENT_LIKE.String(): len(list) > 0,
	}, nil
}

// StatsAtBlog
// 是否已点赞、已收藏
func (s *InterestServiceImpl) StatsAtBlog(ctx context.Context, blogId string, userId string) (map[string]bool, error) {
	query := &model.CollectQuery{
		UserId:   userId,
		TargetId: blogId,
		CollectTypes: []string{
			model.BLOG_LIKE.String(),
			model.BLOG_FAVORITE.String(),
		},
	}
	collects, err := s.collectRelationRepository.FindListByQuery(query)
	if err != nil {
		logrus.Errorf("[aid: %s] FindListByQuery 时出错. err = %v", ctx.Value("aid"), err.Error())
		return nil, err
	}

	//是否已收藏、已点赞
	collectsMap := lo.SliceToMap(collects, func(item *model.CollectRelation) (string, bool) {
		return item.CollectType, true
	})
	return collectsMap, nil
}

// StatsAtUser
// 是否已关注、已拉黑
func (s *InterestServiceImpl) StatsAtUser(ctx context.Context, targetUserId string, userId string) (map[string]bool, error) {
	if userId == targetUserId {
		return nil, errors.New("不能查询自己对自己的关注状态")
	}
	followed, err := s.interestRepository.ExistsFollowId(targetUserId, userId)
	blacked, err := s.interestRepository.ExistsBlackId(targetUserId, userId)

	return map[string]bool{
		"followed": followed,
		"blacked":  blacked,
	}, err
}

func (s *InterestServiceImpl) GetInterest(ctx context.Context, userId string) (*model.UserInterest, error) {
	return s.interestRepository.FindByUserId(userId)
}

func (s *InterestServiceImpl) GetFavorites(ctx context.Context, userId string) ([]string, error) {
	query := &model.CollectQuery{
		UserId:       userId,
		CollectTypes: []string{model.BLOG_FAVORITE.String()},
	}
	list, err := s.collectRelationRepository.FindListByQuery(query)
	if err != nil {
		logrus.Errorf("[aid: %s] FindListByQuery 时出错. err = %v", ctx.Value("aid"), err.Error())
		return nil, err
	}
	favoritesIds := lo.Map(list, func(item *model.CollectRelation, _ int) string {
		return item.TargetId
	})
	return favoritesIds, nil
}
